home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Date / Span.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  30.8 KB  |  960 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
  3. //
  4. // +----------------------------------------------------------------------+
  5. // | Copyright (c) 1997-2005  Leandro Lucarella, Pierre-Alain Joye        |
  6. // +----------------------------------------------------------------------+
  7. // | This source file is subject to the New BSD license, That is bundled  |
  8. // | with this package in the file LICENSE, and is available through      |
  9. // | the world-wide-web at                                                |
  10. // | http://www.opensource.org/licenses/bsd-license.php                   |
  11. // | If you did not receive a copy of the new BSDlicense and are unable   |
  12. // | to obtain it through the world-wide-web, please send a note to       |
  13. // | pear-dev@lists.php.net so we can mail you a copy immediately.        |
  14. // +----------------------------------------------------------------------+
  15. // | Author: Baba Buehler <baba@babaz.com>                                |
  16. // |         Pierre-Alain Joye <pajoye@php.net>                           |
  17. // +----------------------------------------------------------------------+
  18.  
  19. /**
  20.  * Generic time span handling class for PEAR
  21.  *
  22.  * PHP versions 4 and 5
  23.  *
  24.  * @category   Date and Time
  25.  * @package    Date
  26.  * @author     Leandro Lucarella <llucax@php.net>
  27.  * @author     Pierre-Alain Joye <pajoye@php.net>
  28.  * @copyright  1997-2005 Leandro Lucarella, Pierre-Alain Joye
  29.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  30.  * @version    CVS: $Id: Span.php,v 1.8 2005/11/15 00:16:40 pajoye Exp $
  31.  * @link       http://pear.php.net/package/Date
  32.  * @since      File available since Release 1.4
  33.  */
  34.  
  35. /**
  36.  * Get the Date class
  37.  */
  38. require_once 'Date.php';
  39.  
  40. /**
  41.  * Get the Date_Calc class
  42.  */
  43. require_once 'Date/Calc.php';
  44.  
  45. /**
  46.  * Non Numeric Separated Values (NNSV) Input Format.
  47.  *
  48.  * Input format guessed from something like this:
  49.  * days<sep>hours<sep>minutes<sep>seconds
  50.  * Where <sep> is any quantity of non numeric chars. If no values are
  51.  * given, time span is set to zero, if one value is given, it's used for
  52.  * hours, if two values are given it's used for hours and minutes and if
  53.  * three values are given, it's used for hours, minutes and seconds.<br>
  54.  * Examples:<br>
  55.  * ''                   -> 0, 0, 0, 0 (days, hours, minutes, seconds)<br>
  56.  * '12'                 -> 0, 12, 0, 0
  57.  * '12.30'              -> 0, 12, 30, 0<br>
  58.  * '12:30:18'           -> 0, 12, 30, 18<br>
  59.  * '3-12-30-18'         -> 3, 12, 30, 18<br>
  60.  * '3 days, 12-30-18'   -> 3, 12, 30, 18<br>
  61.  * '12:30 with 18 secs' -> 0, 12, 30, 18<br>
  62.  *
  63.  * @const int
  64.  */
  65. define('DATE_SPAN_INPUT_FORMAT_NNSV', 1);
  66.  
  67. /**
  68.  * Default time format when converting to a string.
  69.  *
  70.  * @global string
  71.  */
  72. $GLOBALS['_DATE_SPAN_FORMAT']  = '%C';
  73.  
  74. /**
  75.  * Default time format when converting from a string.
  76.  *
  77.  * @global mixed
  78.  */
  79. $GLOBALS['_DATE_SPAN_INPUT_FORMAT'] = DATE_SPAN_INPUT_FORMAT_NNSV;
  80.  
  81. /**
  82.  * Generic time span handling class for PEAR
  83.  *
  84.  * @author     Leandro Lucarella <llucax@php.net>
  85.  * @copyright  1997-2005 The PHP Group
  86.  * @license    http://www.opensource.org/licenses/bsd-license.php  New BSD License
  87.  * @version    Release: 1.4.6
  88.  * @link       http://pear.php.net/package/Date
  89.  * @since      Class available since Release 1.4
  90.  *
  91.  * @todo       Get and set default local input and output formats?
  92.  */
  93. class Date_Span {
  94.  
  95.     /**
  96.      * @var int
  97.      */
  98.     var $day;
  99.  
  100.     /**
  101.      * @var int
  102.      */
  103.     var $hour;
  104.  
  105.     /**
  106.      * @var int
  107.      */
  108.     var $minute;
  109.  
  110.     /**
  111.      * @var int
  112.      */
  113.     var $second;
  114.  
  115.     /**
  116.      * Constructor.
  117.      *
  118.      * Creates the time span object calling the set() method.
  119.      *
  120.      * @param  mixed $time   Time span expression.
  121.      * @param  mixed $format Format string to set it from a string or the
  122.      *                       second date set it from a date diff.
  123.      *
  124.      * @see    set()
  125.      * @access public
  126.      */
  127.     function Date_Span($time = 0, $format = null)
  128.     {
  129.         $this->set($time, $format);
  130.     }
  131.  
  132.     /**
  133.      * Set the time span to a new value in a 'smart' way.
  134.      *
  135.      * Sets the time span depending on the argument types, calling
  136.      * to the appropriate setFromXxx() method.
  137.      *
  138.      * @param  mixed $time   Time span expression.
  139.      * @param  mixed $format Format string to set it from a string or the
  140.      *                       second date set it from a date diff.
  141.      *
  142.      * @return bool  true on success.
  143.      *
  144.      * @see    setFromObject()
  145.      * @see    setFromArray()
  146.      * @see    setFromString()
  147.      * @see    setFromSeconds()
  148.      * @see    setFromDateDiff()
  149.      * @access public
  150.      */
  151.     function set($time = 0, $format = null)
  152.     {
  153.         if (is_a($time, 'date_span')) {
  154.             return $this->copy($time);
  155.         } elseif (is_a($time, 'date') and is_a($format, 'date')) {
  156.             return $this->setFromDateDiff($time, $format);
  157.         } elseif (is_array($time)) {
  158.             return $this->setFromArray($time);
  159.         } elseif (is_string($time)) {
  160.             return $this->setFromString($time, $format);
  161.         } elseif (is_int($time)) {
  162.             return $this->setFromSeconds($time);
  163.         } else {
  164.             return $this->setFromSeconds(0);
  165.         }
  166.     }
  167.  
  168.     /**
  169.      * Set the time span from an array.
  170.      *
  171.      * Set the time span from an array. Any value can be a float (but it
  172.      * has no sense in seconds), for example array(23.5, 20, 0) is
  173.      * interpreted as 23 hours, .5*60 + 20 = 50 minutes and 0 seconds.
  174.      *
  175.      * @param  array $time Items are counted from right to left. First
  176.      *                     item is for seconds, second for minutes, third
  177.      *                     for hours and fourth for days. If there are
  178.      *                     less items than 4, zero (0) is assumed for the
  179.      *                     absent values.
  180.      *
  181.      * @return bool  True on success.
  182.      *
  183.      * @access public
  184.      */
  185.     function setFromArray($time)
  186.     {
  187.         if (!is_array($time)) {
  188.             return false;
  189.         }
  190.         $tmp1 = new Date_Span;
  191.         if (!$tmp1->setFromSeconds(@array_pop($time))) {
  192.             return false;
  193.         }
  194.         $tmp2 = new Date_Span;
  195.         if (!$tmp2->setFromMinutes(@array_pop($time))) {
  196.             return false;
  197.         }
  198.         $tmp1->add($tmp2);
  199.         if (!$tmp2->setFromHours(@array_pop($time))) {
  200.             return false;
  201.         }
  202.         $tmp1->add($tmp2);
  203.         if (!$tmp2->setFromDays(@array_pop($time))) {
  204.             return false;
  205.         }
  206.         $tmp1->add($tmp2);
  207.         return $this->copy($tmp1);
  208.     }
  209.  
  210.     /**
  211.      * Set the time span from a string based on an input format.
  212.      *
  213.      * Set the time span from a string based on an input format. This is
  214.      * some like a mix of format() method and sscanf() PHP function. The
  215.      * error checking and validation of this function is very primitive,
  216.      * so you should be carefull when using it with unknown $time strings.
  217.      * With this method you are assigning day, hour, minute and second
  218.      * values, and the last values are used. This means that if you use
  219.      * something like setFromString('10, 20', '%H, %h') your time span
  220.      * would be 20 hours long. Allways remember that this method set
  221.      * <b>all</b> the values, so if you had a $time span 30 minutes long
  222.      * and you make $time->setFromString('20 hours', '%H hours'), $time
  223.      * span would be 20 hours long (and not 20 hours and 30 minutes).
  224.      * Input format options:<br>
  225.      *  <code>%C</code> Days with time, same as "%D, %H:%M:%S".<br>
  226.      *  <code>%d</code> Total days as a float number
  227.      *                  (2 days, 12 hours = 2.5 days).<br>
  228.      *  <code>%D</code> Days as a decimal number.<br>
  229.      *  <code>%e</code> Total hours as a float number
  230.      *                  (1 day, 2 hours, 30 minutes = 26.5 hours).<br>
  231.      *  <code>%f</code> Total minutes as a float number
  232.      *                  (2 minutes, 30 seconds = 2.5 minutes).<br>
  233.      *  <code>%g</code> Total seconds as a decimal number
  234.      *                  (2 minutes, 30 seconds = 90 seconds).<br>
  235.      *  <code>%h</code> Hours as decimal number.<br>
  236.      *  <code>%H</code> Hours as decimal number limited to 2 digits.<br>
  237.      *  <code>%m</code> Minutes as a decimal number.<br>
  238.      *  <code>%M</code> Minutes as a decimal number limited to 2 digits.<br>
  239.      *  <code>%n</code> Newline character (\n).<br>
  240.      *  <code>%p</code> Either 'am' or 'pm' depending on the time. If 'pm'
  241.      *                  is detected it adds 12 hours to the resulting time
  242.      *                  span (without any checks). This is case
  243.      *                  insensitive.<br>
  244.      *  <code>%r</code> Time in am/pm notation, same as "%H:%M:%S %p".<br>
  245.      *  <code>%R</code> Time in 24-hour notation, same as "%H:%M".<br>
  246.      *  <code>%s</code> Seconds as a decimal number.<br>
  247.      *  <code>%S</code> Seconds as a decimal number limited to 2 digits.<br>
  248.      *  <code>%t</code> Tab character (\t).<br>
  249.      *  <code>%T</code> Current time equivalent, same as "%H:%M:%S".<br>
  250.      *  <code>%%</code> Literal '%'.<br>
  251.      *
  252.      * @param  string $time   String from where to get the time span
  253.      *                        information.
  254.      * @param  string $format Format string.
  255.      *
  256.      * @return bool   True on success.
  257.      *
  258.      * @access public
  259.      */
  260.     function setFromString($time, $format = null)
  261.     {
  262.         if (is_null($format)) {
  263.             $format = $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];
  264.         }
  265.         // If format is a string, it parses the string format.
  266.         if (is_string($format)) {
  267.             $str = '';
  268.             $vars = array();
  269.             $pm = 'am';
  270.             $day = $hour = $minute = $second = 0;
  271.             for ($i = 0; $i < strlen($format); $i++) {
  272.                 $char = $format{$i};
  273.                 if ($char == '%') {
  274.                     $nextchar = $format{++$i};
  275.                     switch ($nextchar) {
  276.                         case 'c':
  277.                             $str .= '%d, %d:%d:%d';
  278.                             array_push(
  279.                                 $vars, 'day', 'hour', 'minute', 'second');
  280.                             break;
  281.                         case 'C':
  282.                             $str .= '%d, %2d:%2d:%2d';
  283.                             array_push(
  284.                                 $vars, 'day', 'hour', 'minute', 'second');
  285.                             break;
  286.                         case 'd':
  287.                             $str .= '%f';
  288.                             array_push($vars, 'day');
  289.                             break;
  290.                         case 'D':
  291.                             $str .= '%d';
  292.                             array_push($vars, 'day');
  293.                             break;
  294.                         case 'e':
  295.                             $str .= '%f';
  296.                             array_push($vars, 'hour');
  297.                             break;
  298.                         case 'f':
  299.                             $str .= '%f';
  300.                             array_push($vars, 'minute');
  301.                             break;
  302.                         case 'g':
  303.                             $str .= '%f';
  304.                             array_push($vars, 'second');
  305.                             break;
  306.                         case 'h':
  307.                             $str .= '%d';
  308.                             array_push($vars, 'hour');
  309.                             break;
  310.                         case 'H':
  311.                             $str .= '%2d';
  312.                             array_push($vars, 'hour');
  313.                             break;
  314.                         case 'm':
  315.                             $str .= '%d';
  316.                             array_push($vars, 'minute');
  317.                             break;
  318.                         case 'M':
  319.                             $str .= '%2d';
  320.                             array_push($vars, 'minute');
  321.                             break;
  322.                         case 'n':
  323.                             $str .= "\n";
  324.                             break;
  325.                         case 'p':
  326.                             $str .= '%2s';
  327.                             array_push($vars, 'pm');
  328.                             break;
  329.                         case 'r':
  330.                             $str .= '%2d:%2d:%2d %2s';
  331.                             array_push(
  332.                                 $vars, 'hour', 'minute', 'second', 'pm');
  333.                             break;
  334.                         case 'R':
  335.                             $str .= '%2d:%2d';
  336.                             array_push($vars, 'hour', 'minute');
  337.                             break;
  338.                         case 's':
  339.                             $str .= '%d';
  340.                             array_push($vars, 'second');
  341.                             break;
  342.                         case 'S':
  343.                             $str .= '%2d';
  344.                             array_push($vars, 'second');
  345.                             break;
  346.                         case 't':
  347.                             $str .= "\t";
  348.                             break;
  349.                         case 'T':
  350.                             $str .= '%2d:%2d:%2d';
  351.                             array_push($vars, 'hour', 'minute', 'second');
  352.                             break;
  353.                         case '%':
  354.                             $str .= "%";
  355.                             break;
  356.                         default:
  357.                             $str .= $char . $nextchar;
  358.                     }
  359.                 } else {
  360.                     $str .= $char;
  361.                 }
  362.             }
  363.             $vals = sscanf($time, $str);
  364.             foreach ($vals as $i => $val) {
  365.                 if (is_null($val)) {
  366.                     return false;
  367.                 }
  368.                 $$vars[$i] = $val;
  369.             }
  370.             if (strcasecmp($pm, 'pm') == 0) {
  371.                 $hour += 12;
  372.             } elseif (strcasecmp($pm, 'am') != 0) {
  373.                 return false;
  374.             }
  375.             $this->setFromArray(array($day, $hour, $minute, $second));
  376.         // If format is a integer, it uses a predefined format
  377.         // detection method.
  378.         } elseif (is_integer($format)) {
  379.             switch ($format) {
  380.                 case DATE_SPAN_INPUT_FORMAT_NNSV:
  381.                     $time = preg_split('/\D+/', $time);
  382.                     switch (count($time)) {
  383.                         case 0:
  384.                             return $this->setFromArray(
  385.                                 array(0, 0, 0, 0));
  386.                         case 1:
  387.                             return $this->setFromArray(
  388.                                 array(0, $time[0], 0, 0));
  389.                         case 2:
  390.                             return $this->setFromArray(
  391.                                 array(0, $time[0], $time[1], 0));
  392.                         case 3:
  393.                             return $this->setFromArray(
  394.                                 array(0, $time[0], $time[1], $time[2]));
  395.                         default:
  396.                             return $this->setFromArray($time);
  397.                     }
  398.                     break;
  399.             }
  400.         }
  401.         return false;
  402.     }
  403.  
  404.     /**
  405.      * Set the time span from a total number of seconds.
  406.      *
  407.      * @param  int  $seconds Total number of seconds.
  408.      *
  409.      * @return bool True on success.
  410.      *
  411.      * @access public
  412.      */
  413.     function setFromSeconds($seconds)
  414.     {
  415.         if ($seconds < 0) {
  416.             return false;
  417.         }
  418.         $sec  = intval($seconds);
  419.         $min  = floor($sec / 60);
  420.         $hour = floor($min / 60);
  421.         $day  = intval(floor($hour / 24));
  422.         $this->second = $sec % 60;
  423.         $this->minute = $min % 60;
  424.         $this->hour   = $hour % 24;
  425.         $this->day    = $day;
  426.         return true;
  427.     }
  428.  
  429.     /**
  430.      * Set the time span from a total number of minutes.
  431.      *
  432.      * @param  float $minutes Total number of minutes.
  433.      *
  434.      * @return bool  True on success.
  435.      *
  436.      * @access public
  437.      */
  438.     function setFromMinutes($minutes)
  439.     {
  440.         return $this->setFromSeconds(round($minutes * 60));
  441.     }
  442.  
  443.     /**
  444.      * Set the time span from a total number of hours.
  445.      *
  446.      * @param  float $hours Total number of hours.
  447.      *
  448.      * @return bool  True on success.
  449.      *
  450.      * @access public
  451.      */
  452.     function setFromHours($hours)
  453.     {
  454.         return $this->setFromSeconds(round($hours * 3600));
  455.     }
  456.  
  457.     /**
  458.      * Set the time span from a total number of days.
  459.      *
  460.      * @param  float $days Total number of days.
  461.      *
  462.      * @return bool  True on success.
  463.      *
  464.      * @access public
  465.      */
  466.     function setFromDays($days)
  467.     {
  468.         return $this->setFromSeconds(round($days * 86400));
  469.     }
  470.  
  471.     /**
  472.      * Set the span from the elapsed time between two dates.
  473.      *
  474.      * Set the span from the elapsed time between two dates. The time span
  475.      * is allways positive, so the date's order is not important.
  476.      *
  477.      * @param  object Date $date1 First Date.
  478.      * @param  object Date $date2 Second Date.
  479.      *
  480.      * @return bool  True on success.
  481.      *
  482.      * @access public
  483.      */
  484.     function setFromDateDiff($date1, $date2)
  485.     {
  486.         if (!is_a($date1, 'date') or !is_a($date2, 'date')) {
  487.             return false;
  488.         }
  489.         $date1->toUTC();
  490.         $date2->toUTC();
  491.         if ($date1->after($date2)) {
  492.             list($date1, $date2) = array($date2, $date1);
  493.         }
  494.         $days = Date_Calc::dateDiff(
  495.             $date1->getDay(), $date1->getMonth(), $date1->getYear(),
  496.             $date2->getDay(), $date2->getMonth(), $date2->getYear()
  497.         );
  498.         $hours = $date2->getHour() - $date1->getHour();
  499.         $mins  = $date2->getMinute() - $date1->getMinute();
  500.         $secs  = $date2->getSecond() - $date1->getSecond();
  501.         $this->setFromSeconds(
  502.             $days * 86400 + $hours * 3600 + $mins * 60 + $secs
  503.         );
  504.         return true;
  505.     }
  506.  
  507.     /**
  508.      * Set the time span from another time object.
  509.      *
  510.      * @param  object Date_Span $time Source time span object.
  511.      *
  512.      * @return bool   True on success.
  513.      *
  514.      * @access public
  515.      */
  516.     function copy($time)
  517.     {
  518.         if (is_a($time, 'date_span')) {
  519.             $this->second = $time->second;
  520.             $this->minute = $time->minute;
  521.             $this->hour   = $time->hour;
  522.             $this->day    = $time->day;
  523.             return true;
  524.         } else {
  525.             return false;
  526.         }
  527.     }
  528.  
  529.     /**
  530.      * Time span pretty printing (similar to Date::format()).
  531.      *
  532.      * Formats the time span in the given format, similar to
  533.      * strftime() and Date::format().<br>
  534.      * <br>
  535.      * Formatting options:<br>
  536.      *  <code>%C</code> Days with time, same as "%D, %H:%M:%S".<br>
  537.      *  <code>%d</code> Total days as a float number
  538.      *                  (2 days, 12 hours = 2.5 days).<br>
  539.      *  <code>%D</code> Days as a decimal number.<br>
  540.      *  <code>%e</code> Total hours as a float number
  541.      *                  (1 day, 2 hours, 30 minutes = 26.5 hours).<br>
  542.      *  <code>%E</code> Total hours as a decimal number
  543.      *                  (1 day, 2 hours, 40 minutes = 26 hours).<br>
  544.      *  <code>%f</code> Total minutes as a float number
  545.      *                  (2 minutes, 30 seconds = 2.5 minutes).<br>
  546.      *  <code>%F</code> Total minutes as a decimal number
  547.      *                  (1 hour, 2 minutes, 40 seconds = 62 minutes).<br>
  548.      *  <code>%g</code> Total seconds as a decimal number
  549.      *                  (2 minutes, 30 seconds = 90 seconds).<br>
  550.      *  <code>%h</code> Hours as decimal number (0 to 23).<br>
  551.      *  <code>%H</code> Hours as decimal number (00 to 23).<br>
  552.      *  <code>%i</code> Hours as decimal number on 12-hour clock
  553.      *                  (1 to 12).<br>
  554.      *  <code>%I</code> Hours as decimal number on 12-hour clock
  555.      *                  (01 to 12).<br>
  556.      *  <code>%m</code> Minutes as a decimal number (0 to 59).<br>
  557.      *  <code>%M</code> Minutes as a decimal number (00 to 59).<br>
  558.      *  <code>%n</code> Newline character (\n).<br>
  559.      *  <code>%p</code> Either 'am' or 'pm' depending on the time.<br>
  560.      *  <code>%P</code> Either 'AM' or 'PM' depending on the time.<br>
  561.      *  <code>%r</code> Time in am/pm notation, same as "%I:%M:%S %p".<br>
  562.      *  <code>%R</code> Time in 24-hour notation, same as "%H:%M".<br>
  563.      *  <code>%s</code> Seconds as a decimal number (0 to 59).<br>
  564.      *  <code>%S</code> Seconds as a decimal number (00 to 59).<br>
  565.      *  <code>%t</code> Tab character (\t).<br>
  566.      *  <code>%T</code> Current time equivalent, same as "%H:%M:%S".<br>
  567.      *  <code>%%</code> Literal '%'.<br>
  568.      *
  569.      * @param  string $format The format string for returned time span.
  570.      *
  571.      * @return string The time span in specified format.
  572.      *
  573.      * @access public
  574.      */
  575.     function format($format = null)
  576.     {
  577.         if (is_null($format)) {
  578.             $format = $GLOBALS['_DATE_SPAN_FORMAT'];
  579.         }
  580.         $output = '';
  581.         for ($i = 0; $i < strlen($format); $i++) {
  582.             $char = $format{$i};
  583.             if ($char == '%') {
  584.                 $nextchar = $format{++$i};
  585.                 switch ($nextchar) {
  586.                     case 'C':
  587.                         $output .= sprintf(
  588.                             '%d, %02d:%02d:%02d',
  589.                             $this->day,
  590.                             $this->hour,
  591.                             $this->minute,
  592.                             $this->second
  593.                         );
  594.                         break;
  595.                     case 'd':
  596.                         $output .= $this->toDays();
  597.                         break;
  598.                     case 'D':
  599.                         $output .= $this->day;
  600.                         break;
  601.                     case 'e':
  602.                         $output .= $this->toHours();
  603.                         break;
  604.                     case 'E':
  605.                         $output .= floor($this->toHours());
  606.                         break;
  607.                     case 'f':
  608.                         $output .= $this->toMinutes();
  609.                         break;
  610.                     case 'F':
  611.                         $output .= floor($this->toMinutes());
  612.                         break;
  613.                     case 'g':
  614.                         $output .= $this->toSeconds();
  615.                         break;
  616.                     case 'h':
  617.                         $output .= $this->hour;
  618.                         break;
  619.                     case 'H':
  620.                         $output .= sprintf('%02d', $this->hour);
  621.                         break;
  622.                     case 'i':
  623.                         $hour =
  624.                             ($this->hour + 1) > 12 ?
  625.                             $this->hour - 12 :
  626.                             $this->hour;
  627.                         $output .= ($hour == 0) ? 12 : $hour;
  628.                         break;
  629.                     case 'I':
  630.                         $hour =
  631.                             ($this->hour + 1) > 12 ?
  632.                             $this->hour - 12 :
  633.                             $this->hour;
  634.                         $output .= sprintf('%02d', $hour==0 ? 12 : $hour);
  635.                         break;
  636.                     case 'm':
  637.                         $output .= $this->minute;
  638.                         break;
  639.                     case 'M':
  640.                         $output .= sprintf('%02d',$this->minute);
  641.                         break;
  642.                     case 'n':
  643.                         $output .= "\n";
  644.                         break;
  645.                     case 'p':
  646.                         $output .= $this->hour >= 12 ? 'pm' : 'am';
  647.                         break;
  648.                     case 'P':
  649.                         $output .= $this->hour >= 12 ? 'PM' : 'AM';
  650.                         break;
  651.                     case 'r':
  652.                         $hour =
  653.                             ($this->hour + 1) > 12 ?
  654.                             $this->hour - 12 :
  655.                             $this->hour;
  656.                         $output .= sprintf(
  657.                             '%02d:%02d:%02d %s',
  658.                             $hour==0 ?  12 : $hour,
  659.                             $this->minute,
  660.                             $this->second,
  661.                             $this->hour >= 12 ? 'pm' : 'am'
  662.                         );
  663.                         break;
  664.                     case 'R':
  665.                         $output .= sprintf(
  666.                             '%02d:%02d', $this->hour, $this->minute
  667.                         );
  668.                         break;
  669.                     case 's':
  670.                         $output .= $this->second;
  671.                         break;
  672.                     case 'S':
  673.                         $output .= sprintf('%02d', $this->second);
  674.                         break;
  675.                     case 't':
  676.                         $output .= "\t";
  677.                         break;
  678.                     case 'T':
  679.                         $output .= sprintf(
  680.                             '%02d:%02d:%02d',
  681.                             $this->hour, $this->minute, $this->second
  682.                         );
  683.                         break;
  684.                     case '%':
  685.                         $output .= "%";
  686.                         break;
  687.                     default:
  688.                         $output .= $char . $nextchar;
  689.                 }
  690.             } else {
  691.                 $output .= $char;
  692.             }
  693.         }
  694.         return $output;
  695.     }
  696.  
  697.     /**
  698.      * Convert time span to seconds.
  699.      *
  700.      * @return int Time span as an integer number of seconds.
  701.      *
  702.      * @access public
  703.      */
  704.     function toSeconds()
  705.     {
  706.         return $this->day * 86400 + $this->hour * 3600 +
  707.             $this->minute * 60 + $this->second;
  708.     }
  709.  
  710.     /**
  711.      * Convert time span to minutes.
  712.      *
  713.      * @return float Time span as a decimal number of minutes.
  714.      *
  715.      * @access public
  716.      */
  717.     function toMinutes()
  718.     {
  719.         return $this->day * 1440 + $this->hour * 60 + $this->minute +
  720.             $this->second / 60;
  721.     }
  722.  
  723.     /**
  724.      * Convert time span to hours.
  725.      *
  726.      * @return float Time span as a decimal number of hours.
  727.      *
  728.      * @access public
  729.      */
  730.     function toHours()
  731.     {
  732.         return $this->day * 24 + $this->hour + $this->minute / 60 +
  733.             $this->second / 3600;
  734.     }
  735.  
  736.     /**
  737.      * Convert time span to days.
  738.      *
  739.      * @return float Time span as a decimal number of days.
  740.      *
  741.      * @access public
  742.      */
  743.     function toDays()
  744.     {
  745.         return $this->day + $this->hour / 24 + $this->minute / 1440 +
  746.             $this->second / 86400;
  747.     }
  748.  
  749.     /**
  750.      * Adds a time span.
  751.      *
  752.      * @param  object Date_Span $time Time span to add.
  753.      *
  754.      * @access public
  755.      */
  756.     function add($time)
  757.     {
  758.         return $this->setFromSeconds(
  759.             $this->toSeconds() + $time->toSeconds()
  760.         );
  761.     }
  762.  
  763.     /**
  764.      * Subtracts a time span.
  765.      *
  766.      * Subtracts a time span. If the time span to subtract is larger
  767.      * than the original, the result is zero (there's no sense in
  768.      * negative time spans).
  769.      *
  770.      * @param  object Date_Span $time Time span to subtract.
  771.      *
  772.      * @access public
  773.      */
  774.     function subtract($time)
  775.     {
  776.         $sub = $this->toSeconds() - $time->toSeconds();
  777.         if ($sub < 0) {
  778.             $this->setFromSeconds(0);
  779.         } else {
  780.             $this->setFromSeconds($sub);
  781.         }
  782.     }
  783.  
  784.     /**
  785.      * Tells if time span is equal to $time.
  786.      *
  787.      * @param  object Date_Span $time Time span to compare to.
  788.      *
  789.      * @return bool   True if the time spans are equal.
  790.      *
  791.      * @access public
  792.      */
  793.     function equal($time)
  794.     {
  795.         return $this->toSeconds() == $time->toSeconds();
  796.     }
  797.  
  798.     /**
  799.      * Tells if this time span is greater or equal than $time.
  800.      *
  801.      * @param  object Date_Span $time Time span to compare to.
  802.      *
  803.      * @return bool   True if this time span is greater or equal than $time.
  804.      *
  805.      * @access public
  806.      */
  807.     function greaterEqual($time)
  808.     {
  809.         return $this->toSeconds() >= $time->toSeconds();
  810.     }
  811.  
  812.     /**
  813.      * Tells if this time span is lower or equal than $time.
  814.      *
  815.      * @param  object Date_Span $time Time span to compare to.
  816.      *
  817.      * @return bool   True if this time span is lower or equal than $time.
  818.      *
  819.      * @access public
  820.      */
  821.     function lowerEqual($time)
  822.     {
  823.         return $this->toSeconds() <= $time->toSeconds();
  824.     }
  825.  
  826.     /**
  827.      * Tells if this time span is greater than $time.
  828.      *
  829.      * @param  object Date_Span $time Time span to compare to.
  830.      *
  831.      * @return bool   True if this time span is greater than $time.
  832.      *
  833.      * @access public
  834.      */
  835.     function greater($time)
  836.     {
  837.         return $this->toSeconds() > $time->toSeconds();
  838.     }
  839.  
  840.     /**
  841.      * Tells if this time span is lower than $time.
  842.      *
  843.      * @param  object Date_Span $time Time span to compare to.
  844.      *
  845.      * @return bool   True if this time span is lower than $time.
  846.      *
  847.      * @access public
  848.      */
  849.     function lower($time)
  850.     {
  851.         return $this->toSeconds() < $time->toSeconds();
  852.     }
  853.  
  854.     /**
  855.      * Compares two time spans.
  856.      *
  857.      * Compares two time spans. Suitable for use in sorting functions.
  858.      *
  859.      * @param  object Date_Span $time1 The first time span.
  860.      * @param  object Date_Span $time2 The second time span.
  861.      *
  862.      * @return int    0 if the time spans are equal, -1 if time1 is lower
  863.      *                than time2, 1 if time1 is greater than time2.
  864.      *
  865.      * @static
  866.      * @access public
  867.      */
  868.     function compare($time1, $time2)
  869.     {
  870.         if ($time1->equal($time2)) {
  871.             return 0;
  872.         } elseif ($time1->lower($time2)) {
  873.             return -1;
  874.         } else {
  875.             return 1;
  876.         }
  877.     }
  878.  
  879.     /**
  880.      * Tells if the time span is empty (zero length).
  881.      *
  882.      * @return bool True is it's empty.
  883.      */
  884.     function isEmpty()
  885.     {
  886.         return !$this->day && !$this->hour && !$this->minute && !$this->second;
  887.     }
  888.  
  889.     /**
  890.      * Set the default input format.
  891.      *
  892.      * @param  mixed $format New default input format.
  893.      *
  894.      * @return mixed Previous default input format.
  895.      *
  896.      * @static
  897.      */
  898.     function setDefaultInputFormat($format)
  899.     {
  900.         $old = $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];
  901.         $GLOBALS['_DATE_SPAN_INPUT_FORMAT'] = $format;
  902.         return $old;
  903.     }
  904.  
  905.     /**
  906.      * Get the default input format.
  907.      *
  908.      * @return mixed Default input format.
  909.      *
  910.      * @static
  911.      */
  912.     function getDefaultInputFormat()
  913.     {
  914.         return $GLOBALS['_DATE_SPAN_INPUT_FORMAT'];
  915.     }
  916.  
  917.     /**
  918.      * Set the default format.
  919.      *
  920.      * @param  mixed $format New default format.
  921.      *
  922.      * @return mixed Previous default format.
  923.      *
  924.      * @static
  925.      */
  926.     function setDefaultFormat($format)
  927.     {
  928.         $old = $GLOBALS['_DATE_SPAN_FORMAT'];
  929.         $GLOBALS['_DATE_SPAN_FORMAT'] = $format;
  930.         return $old;
  931.     }
  932.  
  933.     /**
  934.      * Get the default format.
  935.      *
  936.      * @return mixed Default format.
  937.      *
  938.      * @static
  939.      */
  940.     function getDefaultFormat()
  941.     {
  942.         return $GLOBALS['_DATE_SPAN_FORMAT'];
  943.     }
  944.  
  945.     /**
  946.      * Returns a copy of the object (workarround for PHP5 forward compatibility).
  947.      *
  948.      * @return object Date_Span Copy of the object.
  949.      */
  950.     function __clone() {
  951.         $c = get_class($this);
  952.         $s = new $c;
  953.         $s->day    = $this->day;
  954.         $s->hour   = $this->hour;
  955.         $s->minute = $this->minute;
  956.         $s->second = $this->second;
  957.         return $s;
  958.     }
  959. }
  960.